// ElasticsearchServiceCollectionExtensions.cs
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Elastic.Clients.Elasticsearch;
using Elastic.Transport;

namespace Beauty.Net.Elasticsearch
{
    /// <summary>
    /// Elasticsearch服务注册扩展
    /// </summary>
    public static class ElasticsearchServiceCollectionExtensions
    {
        /// <summary>
        /// 添加Elasticsearch服务
        /// </summary>
        /// <param name="services">服务集合</param>
        /// <param name="configureOptions">配置委托</param>
        /// <returns>服务集合</returns>
        public static IServiceCollection AddElasticsearch(this IServiceCollection services, Action<ElasticsearchConfig> configureOptions)
        {
            if (configureOptions == null)
            {
                throw new ArgumentNullException(nameof(configureOptions));
            }

            // 配置选项
            var options = new ElasticsearchConfig();
            configureOptions(options);
            services.AddSingleton(options);

            // 注册Elasticsearch客户端
            RegisterElasticsearchClient(services, options);

            // 注册核心服务
            services.TryAddSingleton<IElasticsearchService, ElasticsearchService>();

            return services;
        }

        /// <summary>
        /// 注册Elasticsearch客户端
        /// </summary>
        private static void RegisterElasticsearchClient(IServiceCollection services, ElasticsearchConfig options)
        {
            if (options == null || options.Nodes == null || !options.Nodes.Any())
            {
                throw new ArgumentException("Elasticsearch configuration is invalid: Nodes are required");
            }

            // 验证所有节点URL
            var validNodes = options.Nodes.Where(node => Uri.TryCreate(node, UriKind.Absolute, out _)).ToList();
            if (!validNodes.Any())
            {
                throw new ArgumentException("No valid Elasticsearch node URLs provided");
            }

            // 创建客户端配置
            var settings = new ElasticsearchClientSettings(new Uri(validNodes.First()));

            // 配置所有节点
            if (validNodes.Count > 1)
            {
                var uris = validNodes.Select(u => new Uri(u)).ToArray();
                var pool = new StaticNodePool(uris);
                settings = new ElasticsearchClientSettings(pool);
            }

            // 如果有用户名和密码，添加认证
            if (!string.IsNullOrEmpty(options.Username) && !string.IsNullOrEmpty(options.Password))
            {
                settings = settings.Authentication(new BasicAuthentication(options.Username, options.Password));
            }

            // 启用HTTPS
            if (validNodes.Any(node => node.StartsWith("https://")))
            {
                settings = settings.ServerCertificateValidationCallback(CertificateValidations.AllowAll);
            }

            // 注册客户端
            services.AddSingleton(_ => new ElasticsearchClient(settings));
        }

        /// <summary>
        /// 添加Elasticsearch服务（从配置中读取）
        /// </summary>
        /// <param name="services">服务集合</param>
        /// <param name="configuration">配置对象</param>
        /// <param name="sectionName">配置节名称</param>
        /// <returns>服务集合</returns>
        public static IServiceCollection AddElasticsearch(this IServiceCollection services, IConfiguration configuration, string sectionName = "Elasticsearch")
        {
            if (configuration == null)
            {
                throw new ArgumentNullException(nameof(configuration));
            }

            // 使用ConfigurationBinder.Get方法获取配置
            var options = new ElasticsearchConfig();
            configuration.GetSection(sectionName).Bind(options);
            services.AddSingleton(options);

            // 注册Elasticsearch客户端
            RegisterElasticsearchClient(services, options);

            // 注册核心服务
            services.TryAddSingleton<IElasticsearchService, ElasticsearchService>();

            return services;
        }

        /// <summary>
        /// 添加Elasticsearch服务（使用默认配置）
        /// </summary>
        /// <param name="services">服务集合</param>
        /// <param name="nodeUrl">节点地址</param>
        /// <returns>服务集合</returns>
        public static IServiceCollection AddElasticsearch(this IServiceCollection services, string nodeUrl)
        {
            if (string.IsNullOrEmpty(nodeUrl))
            {
                throw new ArgumentNullException(nameof(nodeUrl));
            }

            // 验证URL格式
            if (!Uri.TryCreate(nodeUrl, UriKind.Absolute, out _))
            {
                throw new ArgumentException("Invalid Elasticsearch node URL format", nameof(nodeUrl));
            }

            // 使用默认配置
            var options = new ElasticsearchConfig
            {
                Nodes = new List<string> { nodeUrl }
            };
            services.AddSingleton(options);

            // 注册Elasticsearch客户端
            RegisterElasticsearchClient(services, options);

            // 注册核心服务
            services.TryAddSingleton<IElasticsearchService, ElasticsearchService>();

            return services;
        }

        /// <summary>
        /// 添加Elasticsearch服务（使用多个节点）
        /// </summary>
        /// <param name="services">服务集合</param>
        /// <param name="nodeUrls">节点地址列表</param>
        /// <returns>服务集合</returns>
        public static IServiceCollection AddElasticsearch(this IServiceCollection services, IEnumerable<string> nodeUrls)
        {
            if (nodeUrls == null || !nodeUrls.Any())
            {
                throw new ArgumentNullException(nameof(nodeUrls));
            }

            // 使用多节点配置，确保不包含null值和无效URL
            var validNodes = nodeUrls.Where(node => !string.IsNullOrEmpty(node) && Uri.TryCreate(node, UriKind.Absolute, out _)).ToList();
            if (!validNodes.Any())
            {
                throw new ArgumentException("No valid Elasticsearch node URLs provided");
            }

            var options = new ElasticsearchConfig
            {
                Nodes = validNodes
            };
            services.AddSingleton(options);

            // 注册Elasticsearch客户端
            RegisterElasticsearchClient(services, options);

            // 注册核心服务
            services.TryAddSingleton<IElasticsearchService, ElasticsearchService>();

            return services;
        }

        /// <summary>
        /// 添加Elasticsearch服务（使用连接字符串）
        /// </summary>
        /// <param name="services">服务集合</param>
        /// <param name="connectionString">连接字符串（格式：http://user:password@host:port）</param>
        /// <returns>服务集合</returns>
        public static IServiceCollection AddElasticsearchWithConnectionString(this IServiceCollection services, string connectionString)
        {
            if (string.IsNullOrEmpty(connectionString))
            {
                throw new ArgumentNullException(nameof(connectionString));
            }

            try
            {
                // 解析连接字符串
                var uri = new Uri(connectionString);
                var options = new ElasticsearchConfig
                {
                    Nodes = new List<string> { connectionString }
                };

                // 提取用户名和密码
                if (!string.IsNullOrEmpty(uri.UserInfo))
                {
                    var userInfo = uri.UserInfo.Split(':');
                    if (userInfo.Length >= 1)
                    {
                        options.Username = Uri.UnescapeDataString(userInfo[0]);
                    }
                    if (userInfo.Length >= 2)
                    {
                        options.Password = Uri.UnescapeDataString(userInfo[1]);
                    }
                }

                services.AddSingleton(options);
                // 注册Elasticsearch客户端
                RegisterElasticsearchClient(services, options);
                services.TryAddSingleton<IElasticsearchService, ElasticsearchService>();

                return services;
            }
            catch (Exception ex)
            {
                throw new ArgumentException("Invalid connection string format", nameof(connectionString), ex);
            }
        }
    }
}